package com.nova.edc.service.energy.impl;

import com.nova.edc.dao.energy.GatherDao;
import com.nova.edc.model.system.AreaPoint;
import com.nova.edc.model.energy.Gather;
import com.nova.edc.model.system.ModelConstant;
import com.nova.edc.service.energy.GatherService;
import com.nova.edc.service.system.CustomerInfoService;
import com.nova.edc.service.system.DeviceTypeService;
import com.nova.frame.dao.buzz.query.Order;
import com.nova.frame.dao.buzz.query.Query;
import com.nova.frame.dao.criterion.Restrictions;
import com.nova.frame.dao.pager.Page;
import com.nova.frame.dao.parsing.SQLParser;
import com.nova.frame.utils.DateUtils;
import com.nova.frame.utils.JdbcUtils;
import com.nova.module.sql.SqlBuffer;
import com.seio.edc.common.Constants;
import com.seio.edc.util.AssitDateUtil;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;


import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;

/**
 * Created by Administrator on 2016/3/2 0002.
 */
public class GatherServiceImpl implements GatherService {

    @Autowired
    private GatherDao novaGatherDao;
    @Autowired
    private CustomerInfoService novaCustomerInfoService;
    @Autowired
    private DeviceTypeService novaDeviceTypeService;

    private Date missionStartTime;
    private Date selectStartTime;
    private Date insertStartTime;
    private long selectTime;
    private int errorState = ModelConstant.GATHER_ERRORSTATE;

    private int errorTime = ModelConstant.GATHER_ERRORTIME;

    private Logger log = Logger.getLogger(Gather.class);


    @Override
    public List<Gather> findOneToday(String startday, String endday, AreaPoint areaPoint, Integer state) {
        missionStartTime = new Date();
        List<Gather> finalgatherList = new ArrayList<Gather>();
        Timestamp startData = Timestamp.valueOf(startday);
        Timestamp endData = Timestamp.valueOf(endday);
        String sql = "SELECT gateway_id,gateway_logo FROM gateway_conf WHERE gateway_logo = ? ";
        List<Map<String, Object>> mapList = JdbcUtils.queryMap(sql, areaPoint.getGatewayid());
        String sqladd = "";
        if (areaPoint.getSensorid() != null && areaPoint.getSensorid() != 0) {
            sqladd = sqladd + " AND sensor_name = " + areaPoint.getSensorid();
        }
        if (areaPoint.getChannelid() != null && areaPoint.getChannelid() != 0) {
            sqladd = sqladd + " AND channel_name = " + areaPoint.getChannelid();
        }
        if ((int) state != ModelConstant.GATHER_ERRORSTATE) {
            sqladd = sqladd + " AND value = " + state;
        }
        for (Map<String, Object> map : mapList) {
            String tableName = "iot_history_" + map.get("gateway_id");
            String dataSql = "SELECT gateway_logo gatewayid, sensor_name sensorid, channel_name channelid," +
                    " to_char(data_time, 'yyyy-mm-dd hh24:mi:00')  startdate,min(value) activestate FROM " + tableName +
                    " WHERE gateway_logo = ? " + sqladd +
                    " AND data_time between ? AND ? " +
                    " GROUP BY gateway_logo, sensor_name, channel_name, to_char(data_time,'yyyy-mm-dd hh24:mi:00') ,value" +
                    " ORDER BY gateway_logo,sensor_name,channel_name,startdate ASC";
            List<Gather> gatherLists = JdbcUtils.query(Gather.class, dataSql, areaPoint.getGatewayid(), startData, endData);
            if (gatherLists.size() > 0) {
                excuteSelect(gatherLists, finalgatherList);
            }
        }
        return finalgatherList;
    }


    public void excuteSelect(List<Gather> gatherLists, List<Gather> finalgathers) {
        int index = 0;
        for (int i = 0; i < gatherLists.size(); i++) {
            if (ifTheSame(gatherLists, i)) {
                List<Gather> gatherList = new ArrayList<Gather>();
                gatherList.addAll(gatherLists.subList(index, i + 1));
                index = i + 1;
                checkErrorTime(gatherList);
                List<Gather> onegatherfinal = findOnePoint(gatherList);
                correctGatherList(onegatherfinal);
                finalgathers.addAll(onegatherfinal);
            }
        }
    }

    @Override
    public List<Gather> findEveryHour(String gatewayid, Integer sensorid, Integer channelid, String startTime, String endTime) {
        String sql = "SELECT gateway_id, gateway_logo FROM gateway_conf  WHERE gateway_logo = ?";
        List<Map<String, Object>> mapList = JdbcUtils.queryMap(sql, gatewayid);
        if (mapList != null && mapList.size() > 0) {
            String tableName = "iot_history_" + mapList.get(0).get("gateway_id");
            String selsql = "SELECT " +
                    "  gateway_logo                     gatewayid, " +
                    "  sensor_name                      sensorid, " +
                    "  channel_name                     channelid, " +
                    "  to_char(data_time, " +
                    "          'yyyy-mm-dd hh24:00:00') startdate, " +
                    "  sum(value)                       activetime " +
                    " FROM " + tableName +
                    " WHERE gateway_logo  " +
                    " = ? AND sensor_name = ? AND channel_name = ? " +
                    " AND data_time BETWEEN ? AND ? " +
                    " GROUP BY gateway_logo, sensor_name, channel_name, to_char(data_time, 'yyyy-mm-dd hh24:00:00')  " +
                    " ORDER BY startdate ";

            List<Gather> gatherList = JdbcUtils.query(Gather.class, selsql, gatewayid, sensorid, channelid, Timestamp.valueOf(startTime), Timestamp.valueOf(endTime));
            return gatherList;
        } else {
            return null;
        }
    }

    @Override
    public void insertData(String startday, String endday, List<AreaPoint> areaPoints) {
        JdbcUtils.changeDataSource(Constants.COLLECT_DB);
        List<Gather> finalgatherList = findAllToday(startday, endday, areaPoints);
        JdbcUtils.changeDataSource(Constants.DEFAULT_DB);
        insertStartTime = new Date();
        insertList(finalgatherList);
    }


    @Override
    public List<Gather> findAllToday(String startday, String endday, List<AreaPoint> areaPoints) {
        missionStartTime = new Date();
        List<String> allGateway = getGateway(areaPoints);
        List<Gather> finalgatherList = new ArrayList<Gather>();
        Timestamp startData = Timestamp.valueOf(startday);
        Timestamp endData = Timestamp.valueOf(endday);
        String sql = "SELECT gateway_id,gateway_logo FROM gateway_conf ";
        List<Map<String, Object>> mapList = JdbcUtils.queryMap(sql);
        int timeCount = 0;
        for (Map<String, Object> map : mapList) {
            one:
            for (int i = 0; i < allGateway.size(); i++) {
                if (((String) map.get("gateway_logo")).trim().equals(allGateway.get(i).trim())) {
                    selectStartTime = new Date();
                    String tableName = "iot_history_" + map.get("gateway_id");
                    String dataSql = "SELECT gateway_logo gatewayid, sensor_name sensorid, channel_name channelid, " +
                            " to_char(data_time, 'yyyy-mm-dd hh24:mi:00')  startdate, MAX(value) activestate FROM " + tableName +
                            " WHERE gateway_logo = ?  " +
                            " AND data_time between ? AND ? " +
                            " GROUP BY gateway_logo, sensor_name, channel_name, to_char(data_time,'yyyy-mm-dd hh24:mi:00') " +
                            " ORDER BY gateway_logo, sensor_name, channel_name, startdate ASC";
                    List<Gather> gatherLists = JdbcUtils.query(Gather.class, dataSql, allGateway.get(i), startData, endData);
                    timeCount++;
                    log.info(" " + timeCount + "/" + allGateway.size() + "   节点 " + allGateway.get(i).trim() + " 共" + gatherLists.size() + "条数据。 内存使用状况："
                            + Runtime.getRuntime().freeMemory() + "/" + Runtime.getRuntime().totalMemory());
                    Date selectEndTime = new Date();
                    selectTime = selectTime + selectEndTime.getTime() - selectStartTime.getTime();
                    if (gatherLists.size() > 0) {
                        excuteSelect(gatherLists, finalgatherList, areaPoints);
                    }
                    break one;
                }
            }

        }
        return finalgatherList;
    }

    public void excuteSelect(List<Gather> gatherLists, List<Gather> finalgathers, List<AreaPoint> areaPoints) {
        int index = 0;
        for (int i = 0; i < gatherLists.size(); i++) {
            if (ifTheSame(gatherLists, i)) {
                List<Gather> gatherList = new ArrayList<Gather>();
                gatherList.addAll(gatherLists.subList(index, i + 1));
                index = i + 1;
                //  checkRepeatTime(gatherList);
                checkErrorTime(gatherList);
                List<Gather> onegatherfinal = findOnePoint(gatherList);
                correctGatherList(onegatherfinal);
                addProperty(onegatherfinal, areaPoints);
                finalgathers.addAll(onegatherfinal);
            }
        }
    }

    public boolean ifTheSame(List<Gather> gatherLists, int i) {
        return i == gatherLists.size() - 1
                || gatherLists.get(i).getChannelid() - gatherLists.get(i + 1).getChannelid() != 0
                || gatherLists.get(i).getSensorid() != gatherLists.get(i + 1).getSensorid()
                || !DateUtils.getDate2Str("yyyy-MM-dd", gatherLists.get(i).getStartdate()).equals(DateUtils.getDate2Str("yyyy-MM-dd", gatherLists.get(i + 1).getStartdate()));
    }

    public List<Gather> findOnePoint(List<Gather> gatherLists) {
        List<Gather> gatherList = new LinkedList<Gather>();
        gatherList.add(gatherLists.get(0));
        int startActivestate = gatherLists.get(0).getActivestate();
        for (int i = 1; i < gatherLists.size(); i++) {
            int nowActivestate = gatherLists.get(i).getActivestate();
            if (startActivestate != nowActivestate || i == gatherLists.size() - 1) {
                String thisTime = gatherLists.get(i).getStartdate().toString();
                String previousTime = gatherList.get(gatherList.size() - 1).getStartdate().toString();
                int activeTime = AssitDateUtil.getSpanMinute(previousTime, thisTime);
                gatherList.get(gatherList.size() - 1).setActivetime(activeTime);
                gatherList.add(gatherLists.get(i));
                startActivestate = gatherLists.get(i).getActivestate();
            }
        }
        return gatherList;
    }


    //检查失效时间
    public void checkErrorTime(List<Gather> gatherLists) {

        for (int i = 0; i < gatherLists.size() - 1; i++) {
            String currentTime = gatherLists.get(i).getStartdate().toString();
            String nextTime = gatherLists.get(i + 1).getStartdate().toString();
            int spanMinute = AssitDateUtil.getSpanMinute(currentTime, nextTime);
            if (spanMinute > errorTime) {
                gatherLists.get(i).setActivestate(errorState);
            }
        }

        String startTime = DateUtils.getDate2Str("yyyy-MM-dd", gatherLists.get(0).getStartdate()) + " 00:00:00";
        String firstTime = gatherLists.get(0).getStartdate().toString();
        if (AssitDateUtil.getSpanMinute(startTime, firstTime) > 0) {
            Gather gather = new Gather();
            gather.setGatewayid(gatherLists.get(0).getGatewayid());
            gather.setSensorid(gatherLists.get(0).getSensorid());
            gather.setChannelid(gatherLists.get(0).getChannelid());
            gather.setActivestate(errorState);
            gather.setStartdate(Timestamp.valueOf(startTime));
            gatherLists.add(0, gather);
        }
        String endTime = DateUtils.getDate2Str("yyyy-MM-dd", DateUtils.getPastdayDate(gatherLists.get(0).getStartdate(), -1)) + " 00:00:00";
        gatherLists.get(gatherLists.size() - 1).setActivestate(errorState);
        Gather gather = new Gather();
        gather.setGatewayid(gatherLists.get(0).getGatewayid());
        gather.setSensorid(gatherLists.get(0).getSensorid());
        gather.setChannelid(gatherLists.get(0).getChannelid());
        gather.setActivestate(errorState);
        gather.setStartdate(Timestamp.valueOf(endTime));
        gatherLists.add(gatherLists.size(), gather);

    }

    //检查重复时间
    public void checkRepeatTime(List<Gather> gatherLists) {

        for (int i = gatherLists.size() - 1; i > 0; i--) {
            String currentTime = gatherLists.get(i).getStartdate().toString();
            String lastTime = gatherLists.get(i - 1).getStartdate().toString();
            int spanMinute = AssitDateUtil.getSpanMinute(currentTime, lastTime);
            if (spanMinute == 0) {
                gatherLists.remove(i);
            }
        }
    }

    public List<Gather> correctGatherList(List<Gather> gatherList) {
        correctActiveTime(gatherList);
        changeActiveTime(gatherList);
        return gatherList;
    }

    //将操作时间小于5的去除
    public void correctActiveTime(List<Gather> gatherList) {

        for (int i = gatherList.size() - 2; i >= 0; i--) {
            if (gatherList.get(i).getActivetime() <= errorTime) {
                gatherList.remove(i);
            }
        }
    }

    //根据开始时间获取动作时间
    public void changeActiveTime(List<Gather> gatherList) {
        for (int i = 0; i < gatherList.size() - 1; i++) {
            String startTime = gatherList.get(i).getStartdate().toString();
            String endTime = gatherList.get(i + 1).getStartdate().toString();
            int activeTime = AssitDateUtil.getSpanMinute(startTime, endTime);
            gatherList.get(i).setActivetime(activeTime);
        }
        gatherList.remove(gatherList.size() - 1);
    }

    //添加节点，区域，公司属性
    public void addProperty(List<Gather> gatherList, List<AreaPoint> areaPoints) {
        loop:
        for (int i = 0; i < areaPoints.size(); i++) {
            if ((areaPoints.get(i).getGatewayid().trim()).equals(gatherList.get(0).getGatewayid().trim())
                    && areaPoints.get(i).getChannelid() - gatherList.get(0).getChannelid() == 0
                    && areaPoints.get(i).getSensorid() - gatherList.get(0).getSensorid() == 0) {
                for (Gather gather : gatherList) {
                    gather.setPointid(areaPoints.get(i).getId());
                    gather.setAreaid(areaPoints.get(i).getAreaid());
                    gather.setCustomerinfoid(areaPoints.get(i).getCustomerinfoid());
                }
                break loop;
            }
        }
    }


    public int insertList(List<Gather> gatherList) {
        int i = 0;
        for (Gather gather : gatherList) {
            novaGatherDao.insert(gather);
            i++;
        }
        Date missionEndTime = new Date();
        System.out.print("查询任务执行共执行" + (missionEndTime.getTime() - missionStartTime.getTime()) / 1000 + "秒。");
        System.out.print("添加任务执行共执行" + (missionEndTime.getTime() - insertStartTime.getTime()) / 1000 + "秒。");
        System.out.print("任务执行共执行" + (missionEndTime.getTime() - missionStartTime.getTime()) / 1000 + "秒。");

        return i;

    }

    public List<String> getGateway(List<AreaPoint> areaPoints) {
        ArrayList<String> strings = new ArrayList<String>();
        HashSet<String> set = new HashSet<String>();
        if (areaPoints != null && areaPoints.size() > 0) {
            for (int i = 0; i < areaPoints.size(); i++) {
                set.add(areaPoints.get(i).getGatewayid());
            }
            strings.addAll(set);
        }

        return strings;
    }

    @Override
    public List<Gather> findExampleOnedate(String date, Gather gather) {

        Query<Gather> query = novaGatherDao.query().add(Restrictions.eq("date_format(StartDate,'%Y-%m-%d')", date));
        if (gather.getPointid() != null && gather.getPointid() != 0) {
            query.add(Restrictions.eq("PointID", gather.getPointid()));
        }
        query.addOrder(Order.asc("StartDate"));
        List<Gather> list = query.list();
        return list;
    }

    @Override
    public List<Gather> disposeforchart(List<Gather> gatherList, String endDate) {
        List<Gather> gathers = new ArrayList<Gather>();
        Gather gather2 = new Gather();
        gather2.setActivestate(ModelConstant.LIGHT_OFF);
        gather2.setStartdate(DateUtils.getStr2LDate(endDate + " 23:59:59"));
        gatherList.add(gather2);
        for (int i = 0; i < gatherList.size() - 1; i++) {
            gathers.add(gatherList.get(i));
            if (gatherList.get(i).getActivestate() == ModelConstant.LIGHT_ON) {
                if (i == gatherList.size() - 2) {
                    gatherList.get(i + 1).setActivestate(ModelConstant.LIGHT_ON);
                } else {
                    Gather gather = new Gather();
                    gather.setActivestate(ModelConstant.LIGHT_ON);
                    gather.setStartdate(gatherList.get(i + 1).getStartdate());
                    gathers.add(gather);
                }
            }
        }
        gathers.add(gatherList.get(gatherList.size() - 1));
        return gathers;
    }

    @Override
    public List<Map<String, Object>> getWarning(Page page, String date, Integer state, List<String> customerGateway, Integer errorTimes, String typeName) {
        if (customerGateway != null && customerGateway.size() > 0) {
            SqlBuffer sqlBuffer = new SqlBuffer(SQLParser.sql("GatherSQL.getWarning"), true);
            String selectSql = sqlBuffer.getSelectSql();
            String countSql = sqlBuffer.getCountSql();
            if (com.nova.frame.utils.StringUtils.isNotNullOrEmpty(typeName)) {
                Integer id = novaDeviceTypeService.getByName(typeName).getId();
                selectSql = selectSql.replace("&", " AND t_area_point.DeviceTypeId = " + id + " ");
                countSql = countSql.replace("&", " AND t_area_point.DeviceTypeId = " + id + " ");
            } else {
                selectSql = selectSql.replace("&", " ");
                countSql = countSql.replace("&", " ");
            }
            List<Map<String, Object>> result = JdbcUtils.query_limit_map(selectSql.replace("#", org.apache.commons.lang3.StringUtils.join(customerGateway, ",")), page, date, state, errorTimes);
            int count = JdbcUtils.count(countSql.replace("#", org.apache.commons.lang3.StringUtils.join(customerGateway, ",")), date, state, errorTimes).intValue();
            page.make(count);
            return result;
        } else {
            return new ArrayList<Map<String, Object>>();
        }
    }

    @Override
    public List<Map<String, Object>> getAllnight(Page page, String date, Integer state, List<String> customerGateway, String limitTime, String typeName) {
        if (customerGateway == null || customerGateway.size() == 0) {
            return new ArrayList<Map<String, Object>>();
        } else {
            SqlBuffer sqlBuffer = new SqlBuffer(SQLParser.sql("GatherSQL.getAllnight"), true);
            String selectSql = sqlBuffer.getSelectSql();
            String countSql = sqlBuffer.getCountSql();
            if (com.nova.frame.utils.StringUtils.isNotNullOrEmpty(typeName)) {
                Integer id = novaDeviceTypeService.getByName(typeName).getId();
                selectSql = selectSql.replace("&", " AND t_area_point.DeviceTypeId = " + id + " ");
                countSql = countSql.replace("&", " AND t_area_point.DeviceTypeId = " + id + " ");
            } else {
                selectSql = selectSql.replace("&", " ");
                countSql = countSql.replace("&", " ");
            }
            List<Map<String, Object>> result =
                    JdbcUtils.query_limit_map(selectSql.replace("#", org.apache.commons.lang3.StringUtils.join(customerGateway, ","))
                            , page, limitTime, state, date);
            int count = JdbcUtils.count(countSql.replace("#", org.apache.commons.lang3.StringUtils.join(customerGateway, ",")), limitTime, state, date).intValue();
            page.make(count);
            return result;
        }
    }

    @Override
    public void getAllnightTime(String limitTime, Integer state, String date, List<Map<String, Object>> list) {
        for (Map<String, Object> map : list) {
            getAllnightTime(limitTime, state, date, map);
        }
    }

    @Override
    public void getAllnightTime(String limitTime, Integer state, String date, Map<String, Object> map) {
        SqlBuffer sqlBuffer = new SqlBuffer(SQLParser.sql("GatherSQL.getAllnightTime"), true);
        List<Gather> query = JdbcUtils.query(Gather.class, sqlBuffer.getSelectSql(), limitTime, state, date, map.get("pointid"));
        Gather gather = query.get(query.size() - 1);
        String endTime = date + " " + limitTime;
        int lastactiveTime = AssitDateUtil.getSpanMinute(gather.getStartdate().toString(), endTime);
        int errortime = gather.getActivetime();
        BigDecimal origintime = (BigDecimal) map.get("activetime");
        int realtime = origintime.intValue() - (errortime - lastactiveTime);
        map.put("activetime", realtime);
    }

    @Override
    public List<Map<String, Object>> getDataMissed(Page page, String date, Integer state, List<String> customerGateway, Integer picketTime) {
        if (customerGateway == null || customerGateway.size() == 0) {
            return new ArrayList<Map<String, Object>>();
        } else {
            SqlBuffer sqlBuffer = new SqlBuffer(SQLParser.sql("GatherSQL.getDataMissed"), true);
            String selectSql = sqlBuffer.getSelectSql();
            String countSql = sqlBuffer.getCountSql();
            List<Map<String, Object>> result =
                    JdbcUtils.query_limit_map(selectSql.replace("#", org.apache.commons.lang3.StringUtils.join(customerGateway, ","))
                            , page, state, date, picketTime);
            int count = JdbcUtils.count(countSql.replace("#", org.apache.commons.lang3.StringUtils.join(customerGateway, ",")), state, date, picketTime).intValue();
            page.make(count);
            return result;
        }
    }
}
